#include "tcp_server_test.h"
#include <arpa/inet.h>

namespace sdx {
TcpServer::TcpServer() { std::cout << "TcpServer construct..." << std::endl; }
TcpServer::~TcpServer() { std::cout << "TcpServer distruct..." << std::endl; }

void TcpServer::createSocket() {
  socketFd = socket(AF_INET, SOCK_STREAM, 0);
  if (socketFd == -1) {
    std::cout << "create socket failed" << std::endl;
    exit(EXIT_FAILURE);
  }
  ret = setsockopt(socketFd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
  if (ret == -1) {
    std::cout << "set socket option failed" << std::endl;
    exit(EXIT_FAILURE);
  }
}
void TcpServer::bindIp() {
  localAddr.sin_port = htons(PORT);       //开放端口
  localAddr.sin_addr.s_addr = INADDR_ANY; // 本机所有网卡ip地址都监听
  localAddr.sin_family = AF_INET;         // ipv4；
  bzero(&localAddr.sin_zero, 8);
  ret = bind(socketFd, (const sockaddr *)&localAddr, sizeof(struct sockaddr));
  if (ret == -1) {
    std::cout << "bind socket failed" << std::endl;
    exit(EXIT_FAILURE);
  }
}
void TcpServer::listenData() {
  ret = listen(socketFd, 8); // 队列20
  if (ret == -1) {
    std::cout << "listen failed" << std::endl;
    exit(EXIT_FAILURE);
  }
}
void TcpServer::acceptMessage() {
  socklen_t remote_addr_len = sizeof(struct sockaddr); // remoteAddr的长度
  acceptFd = accept(socketFd, (struct sockaddr *)&remoteAddr, &remote_addr_len);
  if (acceptFd == -1) {
    std::cout << "accept failed" << std::endl;
    exit(EXIT_FAILURE);
  }
}
int TcpServer::recvMessage() {
  memset(in_buff, 0, MESSAGE_SIZE);
  ret = recv(acceptFd, (void *)in_buff, MESSAGE_SIZE, 0);
  char temp[INET_ADDRSTRLEN];
  std::cout << "receive" << ret << "bytes message from "
            << inet_ntop(AF_INET, &remoteAddr.sin_addr, temp, INET_ADDRSTRLEN)
            << " and the port is " << ntohs(remoteAddr.sin_port)
            << ", and the message is " << in_buff << std::endl;
  return ret;
}
void TcpServer::sendMessage() {
  ret = send(acceptFd, (void *)in_buff, sizeof(in_buff), 0);
}
void TcpServer::closeAccept() {
  std::cout << "close client connection..." << std::endl;
  close(acceptFd);
}
void TcpServer::closeSocket() {
  std::cout << "quiting server..." << std::endl;
  close(socketFd);
}
int TcpServer::getAcceptFd() { return acceptFd; }
int TcpServer::getListenFd() { return socketFd; }

int TcpServer::setFdnonblocking(int fd) { //设为非阻塞
  int oldflag = fcntl(fd, F_GETFL);
  fcntl(fd, F_SETFL, oldflag | O_NONBLOCK);
  return oldflag;
}

void TcpServer::addEpollInFd(int epollFd, int fd, bool enableET) {
  epoll_event event;
  event.events = EPOLLIN;
  event.data.fd = fd;
  if (enableET)
    event.events |= EPOLLET;
  epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &event);
  setFdnonblocking(fd);
}
void TcpServer::EpollWorkInEt(epoll_event *events, int retNum, int epollFd) {
  for (int i = 0; i < retNum; ++i) {
    int eventFd = events[i].data.fd;
    if (eventFd == socketFd) { //假如当前事件FD是listenFd（socketFd）
      acceptMessage();
      addEpollInFd(epollFd, acceptFd, true); //将新建立的acceptFd设为ET
    } else if (events[i].events & EPOLLIN) {
      //这里不会循环触发，所以要重复读数据，确保把数据读完
      std::cout << "event trigger once" << std::endl;
      while (true) {
        memset(in_buff, 0, MESSAGE_SIZE);
        ret = recv(eventFd, (void *)in_buff, MESSAGE_SIZE, 0);
        if (ret < 0) {
          //对于非阻塞IO,下面的条件成立表示数据已经全部读取完毕。此后epo11就能再次触发
          // sockfd上的 EPOLLIN事件,以驱动下一次读操作
          if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
            std::cout << "read later..." << std::endl;
            break;
          }
          close(eventFd);
          break;
        } else if (ret == 0) {
          close(eventFd);
        } else {
          char temp[INET_ADDRSTRLEN];
          std::cout << "receive" << ret << "bytes message from "
                    << inet_ntop(AF_INET, &remoteAddr.sin_addr, temp,
                                 INET_ADDRSTRLEN)
                    << " and the port is " << ntohs(remoteAddr.sin_port)
                    << ", and the message is " << in_buff << std::endl;
        }
      }
    } else {
      std::cout << "something wrong" << std::endl;
    }
  }
}
void TcpServer::EpollWorkInLt(epoll_event *events, int retNum, int epollFd) {
  for (int i = 0; i < retNum; ++i) {
    int eventFd = events[i].data.fd;
    if (eventFd == socketFd) { //假如当前事件FD是listenFd（socketFd）
      acceptMessage();
      addEpollInFd(epollFd, acceptFd, false); //将新建立的acceptFd设为ET
    } else if (events[i].events & EPOLLIN) {
      //这里会循环触发，所以要重复读数据，确保把数据读完
      std::cout << "event trigger once" << std::endl;
      memset(in_buff, 0, MESSAGE_SIZE);
      ret = recv(eventFd, (void *)in_buff, MESSAGE_SIZE, 0);
      if (ret <= 0) {
        close(eventFd);
        continue;
      }
      char temp[INET_ADDRSTRLEN];
      std::cout << "receive" << ret << "bytes message from "
                << inet_ntop(AF_INET, &remoteAddr.sin_addr, temp,
                             INET_ADDRSTRLEN)
                << " and the port is " << ntohs(remoteAddr.sin_port)
                << ", and the message is " << in_buff << std::endl;
    } else {
      std::cout << "somgthing wrong" << std::endl;
    }
  }
}
} // namespace sdx